/*******************************************
Module: zt_pmalloc.c
E-Mail: 24zhutian@gmail.com
Notices: Copyright (c) 2007-2011 ls
*******************************************/
#include "zt_config.h"
#include "zt_malloc.h"
#include "zt_pmalloc.h"

static void *zt_palloc_block(zt_mem_pool_t *pool,size_t siz);
static void *zt_palloc_large(zt_mem_pool_t *pool,size_t siz);

ZT_API zt_mem_pool_t *zt_mempool_create(size_t siz)
{
	zt_mem_pool_t *p;
	p=zt_memalign(ZT_POOL_ALIGNMENT,siz+sizeof(zt_mem_pool_t));
    if(p==NULL){
        return(NULL);
    }
	
    p->pool.str=p->pool.last=(u_char *)p+sizeof(zt_mem_pool_t);
    p->pool.free=siz;
    p->pool.use=p->pool.failed=0;
    p->pool.next=NULL;
    
    p->count=1;
    p->siz=0;
	p->msiz=0;

	p->size=siz+sizeof(zt_mem_pool_t);
    p->max=siz;//(siz<ZT_MAX_MALLOC_FROM_POOL)?siz:ZT_MAX_MALLOC_FROM_POOL;

    p->current=p;
    p->large=NULL;
   
    return(p);
}

ZT_API void zt_mempool_destroy(zt_mem_pool_t *pool)
{
    zt_mem_pool_t *p,*n;
    zt_pool_large_t *l;

	pool->siz=0;
	pool->msiz=0;	
    for(l=pool->large;l;l=l->next){
        if(l->siz>0){
            l->siz=0;
            zt_free(l->str);
            l->str=NULL;
        }
    }
	pool->large=NULL;
	
	pool->count=0;
    for(p=pool,n=pool->pool.next;/* void */;p=n,n=n->pool.next){
        zt_free(p);
        if(n==NULL){
            break;
        }
    }
}

ZT_API void zt_mempool_reset(zt_mem_pool_t *pool)
{
    zt_mem_pool_t *p;
    zt_pool_large_t *l;

    for(l=pool->large;l;l=l->next){
        if(l->siz>0){
            l->siz=0;
            zt_free(l->str);           
            l->str=NULL;
        }
    }
    
    pool->siz=0;
    pool->msiz=0;

    pool->large=NULL;
    for(p=pool;p;p=p->pool.next){
        p->pool.str=p->pool.last=(u_char *)p+sizeof(zt_mem_pool_t);
        p->pool.free=p->max;
        p->pool.use=p->pool.failed=0;
    }
}

ZT_API void *zt_pmalloc(zt_mem_pool_t *pool,size_t siz)
{
	u_char *m;
    zt_mem_pool_t *p;
	
	siz=zt_align(siz,ZT_POOL_ALIGNMENT);
    if(siz<=pool->max){
        p=pool->current;

        do{
            m=p->pool.last;
            if(p->pool.free>=siz){
                p->pool.use+=siz;
                p->pool.free-=siz;
                p->pool.last=m+siz;
                return(m);
            }
			p=p->pool.next;
        }while(p);
        return(zt_palloc_block(pool,siz));
    }
    return(zt_palloc_large(pool,siz));
}

ZT_API void *zt_pnmalloc(zt_mem_pool_t *pool,size_t siz)
{
	u_char *m;
    zt_mem_pool_t *p;	
	
    if(siz<=pool->max){
        p=pool->current;
		
        do{
            m=p->pool.last;
            if(p->pool.free>=siz){
                p->pool.use+=siz;
                p->pool.free-=siz;
                p->pool.last=m+siz;
                return(m);
            }
			p=p->pool.next;
        }while(p);
        return(zt_palloc_block(pool,siz));
    }
    return(zt_palloc_large(pool,siz));
}

ZT_API zt_int_t zt_pfree(zt_mem_pool_t *pool,void *p)
{
    zt_pool_large_t *l;
   
    for(l=pool->large;l;l=l->next){
        if(p==l->str){            
            pool->siz--;
            pool->msiz-=l->siz;
            
            l->siz=0;            
            zt_free(l->str);           
            l->str=NULL;
            return(ZT_OK);
        }
    }
   
    return(ZT_ERR);
}

/*
	new zt_mem_pool_t
*/
static void *zt_palloc_block(zt_mem_pool_t *pool,size_t siz)
{
    u_char *m;    
    zt_mem_pool_t *p,*n,*current;

    m=zt_malloc(pool->size);//zt_memalign(ZT_POOL_ALIGNMENT,psiz);
    if(m==NULL){
        return(NULL);
    }
    n=(zt_mem_pool_t *)m;
	n->max=pool->max;
    n->pool.next=NULL;
    n->pool.failed=0;
	
    m+=sizeof(zt_mem_pool_t);
    n->pool.str=m;	
    n->pool.use=siz;
    n->pool.free=pool->max-siz;
    n->pool.str=n->pool.last=m;
   
    current=pool->current;
    for(p=current;p->pool.next;p=p->pool.next){
        if(p->pool.failed++>4){
            current=p->pool.next;
        }
    }
    p->pool.next=n;
    pool->current=current?current:n;
    
    pool->count++;

    return(m);
}

static void *zt_palloc_large(zt_mem_pool_t *pool,size_t siz)
{
    void *p;
    zt_uint_t n;
    zt_pool_large_t *large;

    p=zt_malloc(siz);
    if(p==NULL){
        return(NULL);
    }
    n=0;
    for(large=pool->large;large;large=large->next){
        if(large->siz==0){
            large->str=p;
            large->siz=siz;
            return(p);
        }
        if(n++>3){
            break;
        }
    }
    large=zt_pmalloc(pool,sizeof(zt_pool_large_t));
    if(large==NULL){
        zt_free(p);
        return(NULL);
    }
    large->str=p;
    large->siz=siz;
    large->next=pool->large;
    pool->large=large;
    
    pool->siz++;
    pool->msiz+=siz;

    return(p);
}

